﻿using LeanApp.Model.Assist;
using MathNet.Numerics.Statistics;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;

namespace LeanApp.Bll
{
    /// <summary>
    /// spc 分析的实体
    /// </summary>
    public class SpcBll
    {
        /// <summary>
        /// 数据源
        /// </summary>
        public List<double> Source { get; set; } = new List<double>();

        /// <summary>
        /// 上偏差
        /// </summary>
        public double UpperDiff { get; set; } = 0;

        /// <summary>
        /// 下偏差
        /// </summary>
        public double LowerDiff { get; set; } = 0;

        /// <summary>
        /// 规格值
        /// </summary>
        public double SpecVal { get; set; } = 0;

        /// <summary>
        /// 数据量
        /// </summary>
        public int N
        {
            get
            {
                return Source.Count;
            }
        }

        /// <summary>
        /// 规格上限
        /// </summary>
        public double USL
        {
            get
            {
                return SpecVal + UpperDiff;
            }
        }
        /// <summary>
        /// 规格下限
        /// </summary>
        public double LSL
        {
            get
            {
                return SpecVal - LowerDiff;
            }
        }

        /// <summary>
        /// 平均值
        /// </summary>
        public double Average
        {
            get
            {
                return Source.Average();
            }
        }

        /// <summary>
        /// 数据的标准差（样本）
        /// </summary>
        public double StdDeviation
        {
            get
            {
                return Statistics.StandardDeviation(Source);
            }
        }

        /// <summary>
        /// Ca制程能力值
        /// </summary>
        public double Ca
        {
            get
            {
                if (StdDeviation == 0)
                {
                    throw new Exception("样本标准差为0，无法计算Ca制程能力值");
                }
                return (USL - LSL) / 6.0 / StdDeviation;
            }
        }

        /// <summary>
        /// 样本最小值
        /// </summary>
        public double Min
        {
            get
            {
                return Math.Round(Source.Min(), 3);
            }
        }

        /// <summary>
        /// 样本25%分位数
        /// </summary>
        public double LowerQuartile
        {
            get
            {
                return Math.Round(Source.LowerQuartile(), 3);
            }
        }

        /// <summary>
        /// 样本中位数
        /// </summary>
        public double Median
        {
            get
            {
                return Math.Round(Source.Median(), 3);
            }
        }

        /// <summary>
        /// 样本75%分位数
        /// </summary>
        public double UpperQuartile
        {
            get
            {
                return Math.Round(Source.UpperQuartile(), 3);
            }
        }

        /// <summary>
        /// 样本最大值
        /// </summary>
        public double Max
        {
            get
            {
                return Math.Round(Source.Max(), 3);
            }
        }

        /// <summary>
        /// Cpk制程能力值
        /// </summary>
        public double Cpk
        {
            get
            {
                if (StdDeviation == 0)
                {
                    throw new Exception("样本标准差为0，无法计算Ca制程能力值");
                }
                double val1 = (USL - Average) / 3.0 / StdDeviation;
                double val2 = (Average - LSL) / 3.0 / StdDeviation;
                return Math.Min(val1, val2);
            }
        }

        /// <summary>
        /// Spc分析结果
        /// </summary>
        public string Result
        {
            get
            {
                if (Cpk < 0.67)
                {
                    ResultBrush = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromArgb(Color.DarkRed.A, Color.DarkRed.R, Color.DarkRed.G, Color.DarkRed.B));
                    return "不可接受";
                }
                else if (Cpk <= 1)
                {
                    ResultBrush = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromArgb(Color.Red.A, Color.Red.R, Color.Red.G, Color.Red.B));
                    return "能力差";
                }
                else if (Cpk <= 1.33)
                {
                    ResultBrush = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromArgb(Color.Orange.A, Color.Orange.R, Color.Orange.G, Color.Orange.B));
                    return "能力尚可";
                }
                else if (Cpk <= 1.67)
                {
                    ResultBrush = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromArgb(Color.GreenYellow.A, Color.GreenYellow.R, Color.GreenYellow.G, Color.GreenYellow.B));
                    return "能力良好";
                }
                else if (Cpk <= 2)
                {
                    ResultBrush = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromArgb(Color.Green.A, Color.Green.R, Color.Green.G, Color.Green.B));
                    return "能力优秀";
                }
                else
                {
                    ResultBrush = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromArgb(Color.DarkGreen.A, Color.DarkGreen.R, Color.DarkGreen.G, Color.DarkGreen.B));
                    return "能力特优";

                }
            }
        }

        /// <summary>
        /// 结果颜色画刷
        /// </summary>
        public System.Windows.Media.Brush ResultBrush
        {
            get; private set;
        }

        /// <summary>
        /// 规格数据集
        /// </summary>
        public List<double> SpecData
        {
            get
            {
                return CreateData(Source, SpecVal);
            }
        }

        /// <summary>
        /// 上控线数据集
        /// </summary>
        public List<double> USLData
        {
            get
            {
                return CreateData(Source, USL);
            }
        }

        /// <summary>
        /// 下控线数据集
        /// </summary>
        public List<double> LSLData
        {
            get
            {
                return CreateData(Source, LSL);
            }
        }

        /// <summary>
        /// 平均线数据集
        /// </summary>
        public List<double> AvgData
        {
            get
            {
                return CreateData(Source, Average);
            }
        }

        /// <summary>
        /// 样本分组数
        /// </summary>
        public int GroupQty
        {
            get
            {
                return Convert.ToInt32(Math.Sqrt(N)) + 1;
            }
        }

        /// <summary>
        /// 极差
        /// </summary>
        public double ExtraDiff
        {
            get
            {
                return Max - Min;
            }
        }

        /// <summary>
        /// 组距
        /// </summary>
        public double GroupDistance
        {
            get
            {
                return ExtraDiff / (GroupQty - 1);
            }
        }

        /// <summary>
        /// 源数据序号
        /// </summary>>
        public List<int> SourceIndex
        {
            get
            {
                if (Source == null || Source.Count <= 0)
                {
                    return new List<int>();
                }
                else
                {
                    List<int> res = new List<int>();
                    for (int i = 0; i < Source.Count; i++)
                    {
                        res.Add(i + 1);
                    }
                    return res;
                }
            }
        }

        /// <summary>
        /// 分组概率
        /// </summary>
        public List<SpcGroupSample> GroupDatas
        {
            get
            {
                List<SpcGroupSample> samples = CreateGroupSample(Min, Max, GroupDistance);
                CalcGroupProbability(Source, samples);
                return samples;
            }
        }

        /// <summary>
        /// 计算分组概率
        /// </summary>
        /// <param name="source">初始概率</param>
        /// <param name="groupData">分组数据</param>
        private void CalcGroupProbability(List<double> source, List<SpcGroupSample> groupData)
        {
            if (groupData == null || groupData.Count <= 0)
            {
                return;
            }
            if (source == null || source.Count <= 0)
            {
                return;
            }
            source.ForEach(a =>
            {
                SpcGroupSample groupItem = groupData.Find(b => b.MinBoundary <= a && b.MaxBoundary > a);
                if (groupItem != null)
                {
                    groupItem.ItemQty = groupItem.ItemQty + 1;
                }
            });

            groupData.ForEach(a => a.GroupRatio = (1.0 * a.ItemQty / source.Count));
        }

        /// <summary>
        /// 构建样本分组
        /// </summary>
        /// <param name="min">极小值</param>
        /// <param name="max">极大值</param>
        /// <param name="groupDistance">样本组距</param>
        /// <returns>构建后的样本分组</returns>
        private List<SpcGroupSample> CreateGroupSample(double min, double max, double groupDistance)
        {
            List<SpcGroupSample> res = new List<SpcGroupSample>();
            res.Add(new SpcGroupSample()
            {
                Index = 1,
                MaxBoundary = min,
                MinBoundary = min - groupDistance,
            });
            double mov = min;
            int groupIndex = 1;
            while (mov < max)
            {
                groupIndex++;
                res.Add(new SpcGroupSample()
                {
                    Index = groupIndex,
                    MaxBoundary = mov + groupDistance,
                    MinBoundary = mov,
                });
                mov = mov + groupDistance;
            }
            if ((mov - max) <= 0.1 * groupDistance)
            {
                res.Add(new SpcGroupSample()
                {
                    Index = groupIndex + 1,
                    MaxBoundary = mov + groupDistance,
                    MinBoundary = mov,
                });
            }
            return res;
        }

        /// <summary>
        /// 创建数据
        /// </summary>
        /// <param name="source">初始数据</param>
        /// <param name="val">目标数据</param>
        /// <returns>创建好的数据集</returns>
        private List<double> CreateData(List<double> source, double val)
        {
            if (source == null || source.Count <= 0)
            {
                return new List<double>();
            }
            else
            {
                List<double> res = new List<double>();
                for (int i = 0; i < source.Count; i++)
                {
                    res.Add(val);
                }
                return res;
            }
        }



    }
}
